package SC12Project.Milestone2.SearchEngine;

import g6.UddiRegistration.JuddiManager;
import g6.UddiRegistration.TransportFactory;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.juddi.v3.client.ClassUtil;
import org.apache.juddi.v3.client.config.UDDIClientContainer;
import org.apache.juddi.v3.client.transport.Transport;
import org.uddi.api_v3.AuthToken;
import org.uddi.api_v3.BindingTemplate;
import org.uddi.api_v3.BusinessDetail;
import org.uddi.api_v3.BusinessEntity;
import org.uddi.api_v3.BusinessService;
import org.uddi.api_v3.FindQualifiers;
import org.uddi.api_v3.FindService;
import org.uddi.api_v3.GetAuthToken;
import org.uddi.api_v3.GetBusinessDetail;
import org.uddi.api_v3.GetServiceDetail;
import org.uddi.api_v3.GetTModelDetail;
import org.uddi.api_v3.Name;
import org.uddi.api_v3.OverviewURL;
import org.uddi.api_v3.ServiceDetail;
import org.uddi.api_v3.ServiceList;
import org.uddi.api_v3.TModelDetail;
import org.uddi.api_v3.TModelInstanceDetails;
import org.uddi.api_v3.TModelInstanceInfo;
import org.uddi.v3_service.DispositionReportFaultMessage;
import org.uddi.v3_service.UDDIInquiryPortType;
import org.uddi.v3_service.UDDISecurityPortType;

public class SearchEngineImplementation implements WSSearchEngine
{
	private static JuddiManager myJuddiManager;
	private String wildCard = "%";
	
	public SearchEngineImplementation() throws DispositionReportFaultMessage, RemoteException{
		if (myJuddiManager == null){
			myJuddiManager = new JuddiManager();
			myJuddiManager.initialize();
			myJuddiManager.authenticateToServer();
		}
	}
		
	public SearchEngineImplementation(JuddiManager juddiManager) {
		// TODO Auto-generated constructor stub
		this.myJuddiManager = juddiManager;
	}

	public List<ServiceInfo> search(String keywords) {
				
		// remove additional spaces between keywords
		keywords = keywords.replaceAll("\\s+", " ");
		// apply tokenizer and extract the keywords
		ArrayList<String> keywordsList = tokenizeTheKeywords(keywords);
		// we pass the keywords List to the function which returns the services that match
		// our keywords 
		List<org.uddi.api_v3.ServiceInfo> sl = getServices(keywordsList);
		
		// the following procedure produces the list of services, and computes all the keys
		// needed to access each model in UDDI in order to have some descriptions for the services
		// we are interested in 
		List<ServiceInfo> answer = new ArrayList<ServiceInfo>();	
		try {
			answer = populateServiceDescription(sl);
		} catch (DispositionReportFaultMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		
		return answer;
	}
	
private List<ServiceInfo> populateServiceDescription(List<org.uddi.api_v3.ServiceInfo> sl) throws DispositionReportFaultMessage, RemoteException
{
	if(!sl.isEmpty()) // we have found something!
	{
		// the final list to be returned!
		List<ServiceInfo> answer = new ArrayList<ServiceInfo>();
		for(org.uddi.api_v3.ServiceInfo service: sl)
		{
			// two variables to be maintained
			String url = "";
			String description = "";
			
			// add the business entity name in the description
			
			GetBusinessDetail getBusinessDetail = new GetBusinessDetail();
			getBusinessDetail.getBusinessKey().add(service.getBusinessKey());		
			UDDIInquiryPortType myInquiryPortType = this.myJuddiManager.getInquiryPortType();
			BusinessDetail businessDetail = myInquiryPortType .getBusinessDetail(getBusinessDetail);
			List<BusinessEntity> list_b = businessDetail.getBusinessEntity();
			
			if(!list_b.isEmpty())
			{
				description += "Business Entity Name: " + list_b.get(0).getName().get(0).getValue() + "\n";
			}
			
			// add the service name in the description
			GetServiceDetail getServiceDetail = new GetServiceDetail();
			getServiceDetail.getServiceKey().add(service.getServiceKey());
			ServiceDetail serviceDetail = myInquiryPortType.getServiceDetail(getServiceDetail);
			List<BusinessService> list_s = serviceDetail.getBusinessService();
			if(!list_s.isEmpty())
			{
				description += "Business Service Name: " + list_s.get(0).getName().get(0).getValue() + "\n";
			}
			
			//  add the Accesspoint use-type(from binding) in the description
		    List<BindingTemplate> list_t = list_s.get(0).getBindingTemplates().getBindingTemplate();
		    if(!list_t.isEmpty())
			{
				description += "Access Point use-type: " + list_t.get(0).getAccessPoint().getUseType() + "\n";
			}
			
		    // we add few information from T-MODEL, in this case we also extract the URL of WS
		    
		    TModelInstanceDetails modelDetails = list_t.get(0).getTModelInstanceDetails();
		    if (modelDetails != null) {
			    List<TModelInstanceInfo> list_tmi= modelDetails.getTModelInstanceInfo();
			    if(!list_tmi.isEmpty())
			    {
			    	String tModelKey = list_tmi.get(0).getTModelKey();    	
			    	GetTModelDetail tmodel = new GetTModelDetail();
			    	tmodel.getTModelKey().add(tModelKey);
			    	TModelDetail tmodelDetail = myInquiryPortType.getTModelDetail(tmodel);
			    	description += "TModel Name: " + tmodelDetail.getTModel().get(0).getName().getValue() + "\n";
			    	description += "TModel Language:" + tmodelDetail.getTModel().get(0).getName().getLang();
			    	  	
			    	//OverviewURL ourl = list_tmi.get(0).getInstanceDetails().getOverviewDoc().get(0).getOverviewURL();
			    	//description += "Overview Doc use-type: " + ourl.getUseType() + "\n";
			    	
			    	url += tmodelDetail.getTModel().get(0).getOverviewDoc().get(0).getOverviewURL().getValue();		    			    	
			    }	
		    }
		    // we finally create an object of ServiceInfo
		    ServiceInfo serviceInfo = new ServiceInfo();
		    serviceInfo.setDescription(description);
		    serviceInfo.setUrl(url);
		    answer.add(serviceInfo);
		}
		return answer;
	}
	return new ArrayList<ServiceInfo>(); // return an empty list!
}
	
	
	private List<org.uddi.api_v3.ServiceInfo> getServices(ArrayList<String> keywordsList)
	{
		String qualifier = "approximateMatch";
		FindQualifiers findQualifier = new FindQualifiers();
		findQualifier.getFindQualifier().add(qualifier);
				
		// we store here the complete list of services queried by these keywords
	    ArrayList<org.uddi.api_v3.ServiceInfo> found_services = new ArrayList<org.uddi.api_v3.ServiceInfo>();
		FindService fs = new FindService();
		fs.setFindQualifiers(findQualifier);
		
		// we go through each keyword in the list and try to find some matchings
		UDDIInquiryPortType myInquiryPortType = this.myJuddiManager.getInquiryPortType();
		ServiceList list = null;
		
		Name findName = new Name();
		findName.setValue(wildCard);
		fs.getName().add(findName);			
		try {				
			list = myInquiryPortType.findService(fs);
		} catch (DispositionReportFaultMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// go through the list of all web services which match the keyword
		if(list != null)
		{
			if (list.getServiceInfos() != null) {
				List<org.uddi.api_v3.ServiceInfo> list_s = list.getServiceInfos().getServiceInfo();
				for(org.uddi.api_v3.ServiceInfo service: list_s)
				{
					// add in the list founded web services
					for (String keyword : keywordsList){
						String nameService = service.getName().get(0).getValue();
						if (nameService.toLowerCase().contains(keyword)){							
							found_services.add(service);
							break;
						}
					}
				}
			}
		}
		
		return found_services;
	}

		
private ArrayList<String> tokenizeTheKeywords(String keywords)
	{
		ArrayList<String> keywordsList = new ArrayList<String>();
		StringTokenizer st = new StringTokenizer(keywords);
		while (st.hasMoreTokens()) 
		{
			keywordsList.add(st.nextToken()); 
	    }
	    return keywordsList; 
	}
		
	
}

